Skip to content

Initialization Module - #3912

Merged
blnicho merged 115 commits into
Pyomo:mainfrom
michaelbynum:initialization
Jun 3, 2026
Merged

Initialization Module#3912
blnicho merged 115 commits into
Pyomo:mainfrom
michaelbynum:initialization

Conversation

@michaelbynum

@michaelbynum michaelbynum commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

Fixes #3878

Summary/Motivation:

This PR adds a module to devel called initialization. The goal of the module is to provide methods to help initialize nonconvex nonlinear programming problems.

Changes proposed in this PR:

  • Add initialization module
  • Add an initialization method that uses a global optimization solver to find a feasible solution
  • Add an initialization method that builds a linear programming approximation using linear least squares
  • Add an initialization method that builds a piecewise linear approximation and iteratively refines it

Legal Acknowledgement

By contributing to this software project, I have read the contribution guide and agree to the following terms and conditions for my contribution:

  1. I agree my contributions are submitted under the BSD license.
  2. I represent I am authorized to make the contributions and grant the license. If my employer has rights to intellectual property that includes these contributions, I represent that I have received permission to make contributions and grant the required license on behalf of that employer.

@michaelbynum

Copy link
Copy Markdown
Contributor Author

I think I am done making changes. This should be ready for a re-review. If I forgot something or did not address a comment appropriately, please let me know.

@michaelbynum

Copy link
Copy Markdown
Contributor Author

And I already lied. I forgot one change. Should be good for a re-review now.

@mrmundt mrmundt left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do have somewhat stronger feelings about model vs nlp on the public-facing functions. Otherwise, this is looking great.

Comment on lines +57 to +58
# stat, x = lp_init_ex()
# stat, x = pwl_init_ex()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Intentionally commented out?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. This was intentional. Just to make it easy to run the example with different methods.

logger.info(
f'solved NLP with {nlp_solver.name}: {res.solution_status}, {res.termination_condition}'
)
if res.solution_status in {SolutionStatus.feasible, SolutionStatus.optimal}:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with Michael - this can be in a separate PR.



def initialize_with_piecewise_linear_approximation(
nlp: BlockData,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

John asked a similar question on I think a test file earlier ("why nlp instead of model?"). For tests, I really don't think it matters, but here, I think it should be model. It'll make more sense to our users if they look at the docs to see model (the Pyomo style standard) rather than nlp.

@michaelbynum michaelbynum Jun 2, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't realize there was a pyomo style standard here. I don't think I agree that model is any more descriptive than nlp. Also, we are not consistent at all. In fact, I think we use m more than model:

find ./ -name "*.py" | xargs grep "(m," | wc -l: 1685
find ./ -name "*.py" | xargs grep "(model," | wc -l: 1025
find ./ -name "*.py" | xargs grep "(instance," | wc -l: 104
find ./ -name "*.py" | xargs grep "(block," | wc -l: 126
find ./ -name "*.py" | xargs grep "(b," | wc -l: 246

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are also many other examples, such as working_blk, working_model, separation_model, subproblem, root, blk, scenario_instance, ef, etc. Some of these argument names have meanings that are significantly more useful than m or model.



def initialize_with_LP_approximation(
nlp: BlockData,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above (model instead of nlp).



def initialize_with_global_opt(
nlp: BlockData,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above (model instead of nlp).

Comment thread pyomo/devel/initialization/pwl_init.py Outdated
michaelbynum and others added 3 commits June 2, 2026 16:49

@jsiirola jsiirola left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two minor changes / questions (and some notes for later development)

Comment thread pyomo/devel/initialization/initialize.py Outdated
Comment thread pyomo/devel/initialization/initialize.py Outdated
return opt


def _setup(nlp):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should setup also relax any discrete variables to continuous domains?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added an exception for now. I want some time to think about what it would mean to allow models with discrete variables.

)


def shallow_clone(m1):

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the future, we should promote this to a standard transformation. Not only does it make a fast shallow copy, but it collapses the entire block structure, which could be useful in a lot of contexts. It could generate more of a "flattened view" into a model than a "shallow copy"?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is a great suggestion. I don't think "view" is the right term. What you get is a valid model. Flattened is very accurate, though...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this fit into the normal transformation workflow? apply_to wouldn't really make sense, and create_using might also not do what you expect. Maybe I'm thinkin about it wrong...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My initial thought would be to have apply_to raise an exception and only support create_using (similar to the dual transform). I would argue that "view" is correct, as when you solve the flattened view, the solution "appears" in the original structured model (because they share variables). If we go down the transformation route, there are questions around other components, though (e.g., should we map results for suffixes back?).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is a good point. I thought that there was an expectation of create_using that a full clone would get created?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess that is where naming and documentation comes in.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea was apply_to is "in-place" and create_using is "out-of-place". There was concern that "in place" and "out of place" were less user friendly, and apply_to and create_using (short for "create a new model using data from model m") were more clear.

"Cloning" only came into play because many transformations (like GDP) are most efficiently written in-place, so the default implementation of create_using is simply to clone and then run apply_to...

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it. That makes sense.

@mrmundt
mrmundt self-requested a review June 3, 2026 16:17
@blnicho

blnicho commented Jun 3, 2026

Copy link
Copy Markdown
Member

One of the GHA jobs is randomly getting stuck so I'm going to merge this without waiting for the last check.

@blnicho
blnicho merged commit e404b97 into Pyomo:main Jun 3, 2026
55 of 58 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Piecewise Nonlinear => PWL nudge

4 participants